package com.hrcx.mystery.utils.quartz;

import com.hrcx.mystery.pojo.EbMysteryScheduleJob;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;

/**
 * @author hzy
 */
@Slf4j
public class ScheduleUtils {

    /**
     * 先来回顾一下 Quartz 的几个重要接口：（建议开启换行阅读）
     * <p>
     * Scheduler（调度器）：Quartz 通过调度器来注册、暂停、删除 Trigger 和 JobDetail。Scheduler 还拥有一个 SchedulerContext，顾名思义就是上下文，通过SchedulerContext 我们可以获取到触发器和任务的一些信息
     * <p>
     * Trigger（触发器）：通过 cron 表达式或是 SimpleScheduleBuilder 等类，指定任务执行的周期。系统时间走到指定的时间的时候，触发器就会触发任务的执行
     * <p>
     * JobDetail（真正需要执行的任务）：JobDetail 接口相当于将 Job 接口包装了一下，Trigger 和 Scheduler 实际用到的都是 JobDetail
     */
    public final static String JOB_NAME = "TASK_";

    /**
     * 获取触发器 Key
     */
    public static TriggerKey getTriggerKey(Long jobId) {
        return TriggerKey.triggerKey(JOB_NAME + jobId);
    }

    /**
     * 获取jobKey
     */
    public static JobKey getJobKey(Long jobId) {
        return JobKey.jobKey(JOB_NAME + jobId);
    }

    /**
     * 获取表达式触发器
     */
    public static CronTrigger getTrigger(Scheduler scheduler, Long jobId) {
        try {
            return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId));
        } catch (SchedulerException e) {
            throw new RuntimeException("获取定时任务Trigger出现异常", e);
        }
    }

    /**
     * 创建定时任务
     * 默认创建就启用
     */
    public static void createEbMysteryScheduleJob(Scheduler scheduler, EbMysteryScheduleJob ebMysteryScheduleJob) {
        try {
            //构建 job 信息
            JobDetail jobDetail = JobBuilder.newJob(ScheduleJob.class).withIdentity(getJobKey(ebMysteryScheduleJob.getJobId())).build();
            //cron条件表达式
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
                    .cronSchedule(ebMysteryScheduleJob.getCron())
                    .withMisfireHandlingInstructionDoNothing();
            //按新的 cronExpression 表达式构建一个新的 trigger
            CronTrigger trigger = TriggerBuilder.newTrigger()
                    //添加认证信息
                    .withIdentity(getTriggerKey(ebMysteryScheduleJob.getJobId()))
                    //开始执行时间
                    .startAt(ebMysteryScheduleJob.getStartTime())
                    //结束执行时间
                    .endAt(ebMysteryScheduleJob.getPauseTime())
                    //添加执行规则
                    .withSchedule(scheduleBuilder).build();
            jobDetail.getJobDataMap().put(EbMysteryScheduleJob.JOB_PARAM_KEY, ebMysteryScheduleJob);
            scheduler.scheduleJob(jobDetail, trigger);
            if (!ebMysteryScheduleJob.getStatus()) {
                pauseJob(scheduler, ebMysteryScheduleJob.getJobId());
            }
        } catch (SchedulerException e) {
            throw new RuntimeException("创建定时任务失败", e);
        }
    }

    /**
     * 更新任务
     */
    public static Boolean updateEbMysteryScheduleJob(Scheduler scheduler, EbMysteryScheduleJob ebMysteryScheduleJob) {
        try {
            TriggerKey triggerKey = getTriggerKey(ebMysteryScheduleJob.getJobId());
            //表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
                    .cronSchedule(ebMysteryScheduleJob.getCron())
                    .withMisfireHandlingInstructionDoNothing();
            //按新的cronExpression表达式重新构建trigger
            CronTrigger trigger = getTrigger(scheduler, ebMysteryScheduleJob.getJobId());
            trigger = trigger.getTriggerBuilder()
                    //添加认证信息
                    .withIdentity(triggerKey)
                    //添加执行规则
                    .withSchedule(scheduleBuilder)
                    //开始执行时间
                    .startAt(ebMysteryScheduleJob.getStartTime())
                    //结束执行时间
                    .endAt(ebMysteryScheduleJob.getPauseTime())
                    .build();
            trigger.getJobDataMap().put(EbMysteryScheduleJob.JOB_PARAM_KEY, ebMysteryScheduleJob);
            scheduler.rescheduleJob(triggerKey, trigger);
            if (!ebMysteryScheduleJob.getStatus()) {
                //暂停任务
                pauseJob(scheduler, ebMysteryScheduleJob.getJobId());
            }
            return true;
        } catch (SchedulerException e) {
            throw new RuntimeException("更新定时任务失败", e);
        } catch (NullPointerException e) {
            throw new NullPointerException("任务已不存在!");
        }
    }

    /**
     * 立即执行任务(一次)
     */
    public static Boolean run(Scheduler scheduler, EbMysteryScheduleJob ebMysteryScheduleJob) {
        try {
            //参数
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.put(EbMysteryScheduleJob.JOB_PARAM_KEY, ebMysteryScheduleJob);
            scheduler.triggerJob(getJobKey(ebMysteryScheduleJob.getJobId()), jobDataMap);
            return true;
        } catch (SchedulerException e) {
            throw new RuntimeException("立即执行定时任务失败", e);
        } catch (NullPointerException e) {
            throw new NullPointerException("任务已不存在!");
        }
    }

    /**
     * 停止任务
     */
    public static Boolean pauseJob(Scheduler scheduler, Long jobId) {
        try {
            scheduler.pauseJob(getJobKey(jobId));
            return true;
        } catch (SchedulerException e) {
            throw new RuntimeException("暂停定时任务失败", e);
        } catch (NullPointerException e) {
            throw new NullPointerException("任务已不存在!");
        }
    }

    /**
     * 恢复任务
     */
    public static Boolean resumeJob(Scheduler scheduler, Long jobId) {
        try {
            scheduler.resumeJob(getJobKey(jobId));
            return true;
        } catch (SchedulerException e) {
            throw new RuntimeException("暂停定时任务失败", e);
        } catch (NullPointerException e) {
            throw new NullPointerException("任务已不存在!");
        }
    }

    /**
     * 删除任务
     */
    public static Boolean deleteJob(Scheduler scheduler, Long jobId) {
        try {
            scheduler.deleteJob(getJobKey(jobId));
            return true;
        } catch (SchedulerException e) {
            throw new RuntimeException("删除定时任务失败", e);
        } catch (NullPointerException e) {
            throw new NullPointerException("任务已不存在!");
        }
    }
}
